﻿using UnityEngine;
using UnityEditor;
using UnityEditor.Callbacks;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;

public class BuildScript
{
    const string kAssetBundlesOutputPath = "AssetBundles";
    const string resourcesPath = "Primitives";
    /// <summary>
    /// 制作资源包
    /// </summary>
	public static void BuildAssetBundles()
    {
        string outputPath = Path.Combine(Application.streamingAssetsPath, kAssetBundlesOutputPath);
        outputPath = Path.Combine(outputPath, AssetBundleManager.GetPlatformFolderForAssetBundles(EditorUserBuildSettings.activeBuildTarget));
        if (Directory.Exists(outputPath))
        {
            Directory.Delete(outputPath, true);
        }
        Directory.CreateDirectory(outputPath);

        ResetUsedAssetBundleNames();

        BuildPipeline.BuildAssetBundles(outputPath, 0, EditorUserBuildSettings.activeBuildTarget);

        RecordAssetLocation(outputPath);

        AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
    }

    /// <summary>
    /// 记录每个资源在哪个资源包中
    /// </summary>
    /// <param name="outputPath">输出路径</param>
    static void RecordAssetLocation(string outputPath)
    {
        string[] allAssetBundleNames = AssetDatabase.GetAllAssetBundleNames();

        List<AssetInAssetBundle> assetInfoList = new List<AssetInAssetBundle>();
        for (int i = 0; i < allAssetBundleNames.Length; ++i)
        {
            string manifestPath = outputPath + "/" + allAssetBundleNames[i] + ".manifest";
            string[] assetPaths = GetAssetsPathInAssetBundle(manifestPath);

            for (int j = 0; j < assetPaths.Length; ++j)
            {
                string path = assetPaths[j];
                int index = path.LastIndexOf("/");
                if (index >= 0)
                {
                    path = path.Substring(index + 1);
                    index = path.LastIndexOf(".");
                    if (index >= 0)
                    {
                        string name = path.Substring(0, index);
                        string suffix = path.Substring(index + 1).ToLower();

                        if (suffix.Equals("prefab") || suffix.Equals("xml") || suffix.Equals("unity") || suffix.Equals("bytes") ||
                            suffix.Equals("txt") || suffix.Equals("mp3") || suffix.Equals("wav"))
                        {
                            AssetInAssetBundle info = new AssetInAssetBundle();
                            info.assetName = name;
                            info.assetBundleName = allAssetBundleNames[i];
                            assetInfoList.Add(info);
                        }
                    }
                }
            }
        }

        // 写入到Xml
        XmlDocument xmlDoc = new XmlDocument();
        XmlNode xmlRoot = xmlDoc.CreateElement("RECORDS");
        xmlRoot.InnerText = "";
        xmlDoc.AppendChild(xmlRoot);
        for (int i = 0; i < assetInfoList.Count; ++i)
        {
            XmlNode xmlAssetNode = xmlDoc.CreateElement("RECORD");
            xmlRoot.AppendChild(xmlAssetNode);

            XmlNode xmlAssetName = xmlDoc.CreateElement("Name");
            xmlAssetName.InnerText = assetInfoList[i].assetName;
            xmlAssetNode.AppendChild(xmlAssetName);

            XmlNode xmlAssetBundleName = xmlDoc.CreateElement("AssetBundle");
            xmlAssetBundleName.InnerText = assetInfoList[i].assetBundleName;
            xmlAssetNode.AppendChild(xmlAssetBundleName);
        }
        xmlDoc.Save(outputPath + "/AssetRecord.xml");

        Debug.Log("<color=#00ee00ff>Success to build assetbundles.</color>");
    }

    /// <summary>
    /// 从资源包的Manifest文件中获取到其包含的所有资源路径
    /// </summary>
    /// <param name="assetBundleManifestPath">资源包Manifest文件路径</param>
    /// <returns>所有资源的路径</returns>
    static string[] GetAssetsPathInAssetBundle(string assetBundleManifestPath)
    {
        if (!File.Exists(assetBundleManifestPath))
        {
            return new string[] { };
        }
        List<string> assetPaths = new List<string>();

        StreamReader sr = File.OpenText(assetBundleManifestPath);
        string line = sr.ReadLine();
        while (!string.IsNullOrEmpty(line))
        {
            if (line.Equals("Dependencies"))
            {
                break;
            }

            if (line.Contains("- Assets/"))
            {
                line = line.Substring(2);
                assetPaths.Add(line);
            }

            line = sr.ReadLine();
        }

        sr.Close();
        return assetPaths.ToArray();
    }

    #region New refresh asset bundle name

    static AssetRecordInfoDict resourceRecordDict = new AssetRecordInfoDict();

    /// <summary>
    /// 重新设置使用到的AssetBundle名称
    /// </summary>
    public static void ResetUsedAssetBundleNames()
    {
        resourceRecordDict.ResetAssetRecordDicts();
        // 清理掉ab 包名称信息
        ClearProjectAssetBundleNames();
        // 收集预制件 ab 包名称信息
        CollectPrefabAssetBundleRecords();
        // 收集音效资源
        CollectSoundAssetBundleRecords();
        // 收集配置文件资源信息
        CollectConfigAssetBundleRecords();
        // 收集场景相关的资源信息
        CollectSceneAssetBundleRecords();
        if (!resourceRecordDict.IsContainsRepeartedAssetName)
        {
            resourceRecordDict.ResetProjectAssetBundleNames();
        }
    }

    #region Collect Prefab AssetBundle Records

    /// <summary>
    /// 收集预设的 ab 包名称相关信息
    /// </summary>
    static void CollectPrefabAssetBundleRecords()
    {
        string recordRootPath = Application.dataPath + "/" + resourcesPath;
        // 获取对应收集资源目录下的所有Prefab信息
        string[] prefabFullNameArray = Directory.GetFiles(recordRootPath, "*.prefab", SearchOption.AllDirectories);
        // 遍历所有的预制件收集相关信息
        for (int index = 0; index < prefabFullNameArray.Length; index++)
        {
            // 替换路径中的反斜杠为正斜杠
            string prefabPath = prefabFullNameArray[index].Replace(@"\", "/");
            // 资源相对工程路径 Assets 的路径
            string prefabRelativePath = prefabPath.Substring(prefabPath.LastIndexOf("Assets"));
            // 预制件的名称
            string prefabName = GetFileName(prefabRelativePath);

            resourceRecordDict.AddRecord(ResourceRecordType.Prefab, prefabName, prefabRelativePath, prefabName);

            // 收集预制件依赖资源的内容
            CollectPrefabDependencies(prefabRelativePath, prefabName);
        }
    }

    #region Collect Prefab Dependence

    /// <summary>
    /// 收集预制的相关依赖的资源信息
    /// </summary>
    static void CollectPrefabDependencies(string relativePath, string prefabName)
    {
        GameObject prefabObject = AssetDatabase.LoadAssetAtPath(relativePath, typeof(Object)) as GameObject;
        if (prefabObject == null)
        {
            Debug.LogErrorFormat("Prefab[{0}] is null, please check it! ", relativePath);
            return;
        }

        if (relativePath.IndexOf("/UI") > 0) // 处理UI相关的预制件
        {
            HandleUIPrefabDependencies(prefabObject, relativePath, prefabName);
        }
        else
        {
            HandleNormalPrefabDependencies(prefabObject, relativePath, prefabName);
        }
    }

    #region Handle UI Prefab Dependence

    /// <summary>
    /// 处理UI预制件的依赖项关系
    /// </summary>
    /// <param name="prefabObject"></param>
    /// <param name="relativePath"></param>
    /// <param name="rootPrefabName"></param>
    static void HandleUIPrefabDependencies(GameObject prefabObject, string relativePath, string rootPrefabName)
    {
        Object[] dependenceObjectArray = EditorUtility.CollectDependencies(new Object[] { prefabObject });
        for (int index = 0; index < dependenceObjectArray.Length; index++)
        {
            Object dependenceObject = dependenceObjectArray[index];
            if (dependenceObject == null)
            {
                Debug.LogErrorFormat("UI prefab[{0}] hava null child, please check it!", relativePath);
            }
            else
            {
                System.Type dependenceObjectType = dependenceObject.GetType();
                string dependenceObjectPath = AssetDatabase.GetAssetPath(dependenceObject);
                string dependenceObjectName = GetFileName(dependenceObjectPath);
                if (!string.IsNullOrEmpty(dependenceObjectName))
                {
                    switch (dependenceObjectType.FullName)
                    {
                        case "UnityEngine.Shader":
                            resourceRecordDict.AddRecord(ResourceRecordType.Shader, dependenceObjectName, dependenceObjectPath, rootPrefabName);
                            break;
                        case "UnityEngine.Texture2D":
                            resourceRecordDict.AddRecord(ResourceRecordType.Texture, dependenceObjectName, dependenceObjectPath, rootPrefabName);
                            break;
                        case "UnityEngine.AudioClip":
                            resourceRecordDict.AddRecord(ResourceRecordType.AudioClip, dependenceObjectName, dependenceObjectPath, rootPrefabName);
                            break;
                        default:
                            //Debug.LogWarningFormat("Unhandle type[{0}] of ui dependence resource, please check it! name:[{1}] path:[{2}]", dependenceObjectType.FullName, dependenceObjectName, dependenceObjectPath);
                            break;
                    }
                }
            }
        }
    }

    #endregion

    #region Handle Nomarl Prefab Dependence

    /// <summary>
    /// 处理常规预制件的依赖项(非UI预制件)
    /// </summary>
    /// <param name="rootGameObject"></param>
    /// <param name="relativePath"></param>
    /// <param name="rootPrefabName"></param>
    static void HandleNormalPrefabDependencies(GameObject rootGameObject, string relativePath, string rootPrefabName)
    {
        // 处理动画控制器
        HandleGameObjectUsedAnimator(rootGameObject, rootPrefabName);
        // 处理材质球，着色器，贴图
        HandleGameObjectUsedRenderer(rootGameObject, rootPrefabName);
        // 处理mesh
        HandleGameObjectUsedMesh(rootGameObject, rootPrefabName);
        // 循环处理子对象相关内容
        foreach (Transform childTransform in rootGameObject.transform)
        {
            HandleNormalPrefabDependencies(childTransform.gameObject, relativePath, rootPrefabName);
        }
    }

    /// <summary>
    /// 处理物件使用到的mesh
    /// </summary>
    /// <param name="gameObject"></param>
    private static void HandleGameObjectUsedMesh(GameObject gameObject, string rootPrefabName)
    {
        SkinnedMeshRenderer skinnedMeshRenderer = gameObject.GetComponent<SkinnedMeshRenderer>();
        if (skinnedMeshRenderer != null)
        {
            Mesh mesh = skinnedMeshRenderer.sharedMesh;
            if (mesh != null)
            {
                string meshRelativePath = AssetDatabase.GetAssetPath(mesh);
                string meshName = GetFileName(meshRelativePath);
                resourceRecordDict.AddRecord(ResourceRecordType.Mesh, meshName, meshRelativePath, rootPrefabName);
            }
        }

        MeshFilter meshFilter = gameObject.GetComponent<MeshFilter>();
        if (meshFilter != null && meshFilter.sharedMesh != null)
        {
            string meshRelativePath = AssetDatabase.GetAssetPath(meshFilter.sharedMesh);
            string meshName = GetFileName(meshRelativePath);
            resourceRecordDict.AddRecord(ResourceRecordType.Mesh, meshName, meshRelativePath, rootPrefabName);
        }
    }

    /// <summary>
    /// 处理Renderer 相关的 材质球 shader 和Texture
    /// </summary>
    /// <param name="gameObject"></param>
    /// <param name="rootPrefabName"></param>
    static void HandleGameObjectUsedRenderer(GameObject gameObject, string rootPrefabName)
    {
        //收集材质球信息
        Renderer renderer = gameObject.GetComponent<Renderer>();
        if (renderer != null)
        {
            Material[] materialArray = renderer.sharedMaterials;
            foreach (Material material in materialArray)
            {
                HandleGameObjectUsedMaterial(material, rootPrefabName);
            }
        }
    }

    /// <summary>
    /// 处理物件的材质球
    /// </summary>
    /// <param name="material"></param>
    /// <param name="rootPrefabName"></param>
    static void HandleGameObjectUsedMaterial(Material material, string rootPrefabName)
    {
        if (material != null)
        {
            string materialRelativePath = AssetDatabase.GetAssetPath(material);
            string materialName = GetFileName(materialRelativePath);
            resourceRecordDict.AddRecord(ResourceRecordType.Material, materialName, materialRelativePath, rootPrefabName);
            HandleGameObjectUsedShader(material, rootPrefabName);
        }
    }

    /// <summary>
    /// 处理物件使用到的着色器(shader)
    /// </summary>
    /// <param name="material">材质球</param>
    /// <param name="rootPrefabName"></param>
    static void HandleGameObjectUsedShader(Material material, string rootPrefabName)
    {
        Shader shader = material.shader;
        if (shader != null)
        {
            string shaderRelativePath = AssetDatabase.GetAssetPath(shader);
            string shaderName = GetFileName(shaderRelativePath);
            resourceRecordDict.AddRecord(ResourceRecordType.Shader, shaderName, shaderRelativePath, rootPrefabName);
            // 处理Shader 用到的贴图
            for (int index = 0; index < ShaderUtil.GetPropertyCount(shader); index++)
            {
                if (ShaderUtil.GetPropertyType(shader, index) == ShaderUtil.ShaderPropertyType.TexEnv)
                {
                    string propertyName = ShaderUtil.GetPropertyName(shader, index);
                    Texture texture = material.GetTexture(propertyName);
                    HandleGameObjectUsedTexture(texture, propertyName, rootPrefabName);
                }
            }
        }
    }

    /// <summary>
    /// 处理物件使用到的贴图
    /// </summary>
    /// <param name="texture"></param>
    /// <param name="propertyName"></param>
    /// <param name="rootPrefabName"></param>
    static void HandleGameObjectUsedTexture(Texture texture, string propertyName, string rootPrefabName)
    {
        if (texture != null)
        {
            string textureRelativePath = AssetDatabase.GetAssetPath(texture);
            string textureName = GetFileName(textureRelativePath);
            resourceRecordDict.AddRecord(ResourceRecordType.Texture, textureName, textureRelativePath, rootPrefabName);
        }
    }

    /// <summary>
    /// 处理动画控制器
    /// </summary>
    /// <param name="gameObject"></param>
    /// <param name="rootPrefabName"></param>
    static void HandleGameObjectUsedAnimator(GameObject gameObject, string rootPrefabName)
    {
        // 收集动画控制器
        Animator animator = gameObject.GetComponent<Animator>();
        if (animator != null)
        {
            if (animator.runtimeAnimatorController == null)
            {
                Debug.LogWarningFormat("Animator's runtime animator controller was null in prefab:[{0}] of path[{1}],please check it!", rootPrefabName, AssetDatabase.GetAssetPath(gameObject));
                return;
            }
            string animatorRelativePath = AssetDatabase.GetAssetPath(animator.runtimeAnimatorController);
            string animatorName = GetFileName(animatorRelativePath);
            resourceRecordDict.AddRecord(ResourceRecordType.Animator, animatorName, animatorRelativePath, rootPrefabName);
        }
    }

    #endregion

    #endregion

    #endregion

    /// <summary>
    /// 收集音效相关
    /// </summary>
    static void CollectSoundAssetBundleRecords()
    {
        string recordRootPath = Application.dataPath + "/" + resourcesPath;
        string[] mp3FileArray = Directory.GetFiles(recordRootPath, "*.mp3", SearchOption.AllDirectories);

        for (int index = 0; index < mp3FileArray.Length; index++)
        {
            //替换路径中的反斜杠为正斜杠
            string mp3FileName = mp3FileArray[index].Replace(@"\", "/");
            //截取我们需要的路径
            string fileRelativePath = mp3FileName.Substring(mp3FileName.LastIndexOf("Assets"));
            string fileName = GetFileName(fileRelativePath);

            resourceRecordDict.AddRecord(ResourceRecordType.AudioClip, fileName, fileRelativePath, fileName);
        }

        string[] wavFileArray = Directory.GetFiles(recordRootPath, "*.wav", SearchOption.AllDirectories);
        for (int index = 0; index < wavFileArray.Length; index++)
        {
            //替换路径中的反斜杠为正斜杠
            string wavFileName = wavFileArray[index].Replace(@"\", "/");
            //截取我们需要的路径
            string fileRelativePath = wavFileName.Substring(wavFileName.LastIndexOf("Assets"));
            string fileName = GetFileName(fileRelativePath);

            resourceRecordDict.AddRecord(ResourceRecordType.AudioClip, fileName, fileRelativePath, fileName);
        }
    }

    /// <summary>
    /// 收集配置信息资源包名称
    /// </summary>
    static void CollectConfigAssetBundleRecords()
    {
        string recordRootPath = Application.dataPath + "/" + resourcesPath;
        string[] configFileArray = Directory.GetFiles(recordRootPath, "*.bytes", SearchOption.AllDirectories);
        for (int i = 0, len = configFileArray.Length; i < len; i++)
        {
            //替换路径中的反斜杠为正斜杠
            string configFileFullName = configFileArray[i].Replace(@"\", "/");
            //截取我们需要的路径
            string fileRelativePath = configFileFullName.Substring(configFileFullName.LastIndexOf("Assets"));
            string fileName = GetFileName(fileRelativePath);

            resourceRecordDict.AddRecord(ResourceRecordType.Config, fileName, fileRelativePath, fileName);
        }
    }

    /// <summary>
    /// 收集场景资源包名称
    /// </summary>
    static void CollectSceneAssetBundleRecords()
    {
        string recordRootPath = Application.dataPath + "/" + "Scenes";
        string[] senceFileArray = Directory.GetFiles(recordRootPath, "*.unity", SearchOption.AllDirectories);
        for (int i = 0, len = senceFileArray.Length; i < len; i++)
        {
            //替换路径中的反斜杠为正斜杠
            string sceneFileFullName = senceFileArray[i].Replace(@"\", "/");
            //截取我们需要的路径
            string relativePath = sceneFileFullName.Substring(sceneFileFullName.LastIndexOf("Assets"));
            string sceneName = GetFileName(relativePath);
            if (sceneName.ToLower() == "start")// 开始场景，不载入ab包中
                continue;
            resourceRecordDict.AddRecord(ResourceRecordType.Scene, sceneName, relativePath, sceneName);
        }
    }

    /// <summary>
    /// 清理掉工程的ab 包名称
    /// </summary>
    static void ClearProjectAssetBundleNames()
    {
        EditorUtility.DisplayProgressBar("Clear Asset Bundle Name", "Clear AssetBundle Names...", 0);
        string[] assetBundleNameArray = AssetDatabase.GetAllAssetBundleNames();
        if (assetBundleNameArray.Length > 0)
        {
            float progressDeltaValue = 100f / assetBundleNameArray.Length;
            for (int index = 0; index < assetBundleNameArray.Length; index++)
            {
                AssetDatabase.RemoveAssetBundleName(assetBundleNameArray[index], true);
                EditorUtility.DisplayProgressBar("Clear Asset Bundle Name", string.Format("Remove AssetBundleName of Asset[{0}]", assetBundleNameArray[index]), (index + 1) * progressDeltaValue);
            }
        }
        EditorUtility.DisplayProgressBar("Clear Asset Bundle Name", "Remove all old difined AssetBundleNames", 0);
        // 清理掉没有使用的AB包名称
        AssetDatabase.RemoveUnusedAssetBundleNames();
        EditorUtility.ClearProgressBar();
    }

    /// <summary>
    /// 获取资源文件名称(不包含文件后缀)
    /// </summary>
    /// <param name="path"></param>
    /// <returns></returns>
    public static string GetFileName(string path)
    {
        string fileName = "";
        int startIndex = path.LastIndexOf("/");
        int endIndex = path.LastIndexOf(".");

        if (startIndex != -1 && endIndex != -1)
        {
            fileName = path.Substring(startIndex + 1, endIndex - startIndex - 1);
        }

        return fileName;
    }

    #endregion

}

/// <summary>
/// 资源类型
/// </summary>
enum ResourceRecordType
{
    /// <summary>
    /// 预制件
    /// </summary>
    Prefab,
    /// <summary>
    /// 材质球
    /// </summary>
    Material,
    /// <summary>
    /// 贴图
    /// </summary>
    Texture,
    /// <summary>
    /// 动画
    /// </summary>
    Animator,
    /// <summary>
    /// 音效
    /// </summary>
    AudioClip,
    /// <summary>
    /// 着色器
    /// </summary>
    Shader,
    /// <summary>
    /// 网格
    /// </summary>
    Mesh,
    /// <summary>
    /// 配置信息
    /// </summary>
    Config,
    /// <summary>
    /// 场景
    /// </summary>
    Scene,
}

/// <summary>
/// 资源收集器
/// </summary>
class ResourceRecord
{
    /// <summary>
    /// 资源类型
    /// </summary>
    public ResourceRecordType RecordType { get; set; }

    /// <summary>
    /// 资源相对工程的目录
    /// </summary>
    public string RelativePath { get; set; }

    /// <summary>
    /// 资源名称
    /// </summary>
    public string Name { get; set; }

    /// <summary>
    /// 被引用的次数
    /// </summary>
    public int ReferenceCount { get; set; }

    /// <summary>
    /// 根节点信息，便于后续查找错误
    /// </summary>
    public string RootName { get; set; }
}

/// <summary>
/// 资源信息
/// </summary>
class AssetRecordInfoDict
{
    /// <summary>
    /// 预制件的字典
    /// </summary>
    Dictionary<string, ResourceRecord> m_PrefabRecordDict = new Dictionary<string, ResourceRecord>();

    /// <summary>
    /// 材质球字典
    /// </summary>
    Dictionary<string, ResourceRecord> m_MaterialRecordDict = new Dictionary<string, ResourceRecord>();

    /// <summary>
    /// 贴图的字典
    /// </summary>
    Dictionary<string, ResourceRecord> m_TextureRecordDict = new Dictionary<string, ResourceRecord>();

    /// <summary>
    /// Shader 字典
    /// </summary>
    Dictionary<string, ResourceRecord> m_ShaderRecordDict = new Dictionary<string, ResourceRecord>();
    /// <summary>
    /// 音效记录字典
    /// </summary>
    Dictionary<string, ResourceRecord> m_AudioRecordDict = new Dictionary<string, ResourceRecord>();
    /// <summary>
    /// 网格记录字典
    /// </summary>
    Dictionary<string, ResourceRecord> m_MeshRecordDict = new Dictionary<string, ResourceRecord>();

    /// <summary>
    /// 动画控制器记录字典
    /// </summary>
    Dictionary<string, ResourceRecord> m_AnimationRecordDict = new Dictionary<string, ResourceRecord>();

    /// <summary>
    /// 配置文件字典信息
    /// </summary>
    Dictionary<string, ResourceRecord> m_ConfigRecordDict = new Dictionary<string, ResourceRecord>();

    /// <summary>
    /// 场景记录字典
    /// </summary>
    Dictionary<string, ResourceRecord> m_SceneRecordDict = new Dictionary<string, ResourceRecord>();

    public bool IsContainsRepeartedAssetName { get; private set; }

    /// <summary>
    /// 重置记录字典相关内容
    /// </summary>
    public void ResetAssetRecordDicts()
    {
        IsContainsRepeartedAssetName = false;
        m_PrefabRecordDict.Clear();
        m_MaterialRecordDict.Clear();
        m_ShaderRecordDict.Clear();
        m_TextureRecordDict.Clear();

        m_AnimationRecordDict.Clear();

        m_MeshRecordDict.Clear();

        m_AudioRecordDict.Clear();

        m_ConfigRecordDict.Clear();
    }

    /// <summary>
    /// 重置工程的AssetBundleName 名称
    /// </summary>
    public void ResetProjectAssetBundleNames()
    {
        // 不包含重复的名称，可以执行替换ab 包名称了
        if (!IsContainsRepeartedAssetName)
        {
            foreach (var item in m_PrefabRecordDict) // 预制件
            {
                ResetAssetBundleNameByRecord(item.Value, true);
            }

            foreach (var item in m_MaterialRecordDict)
            {
                ResetAssetBundleNameByRecord(item.Value);
            }

            foreach (var item in m_TextureRecordDict)
            {
                ResetAssetBundleNameByRecord(item.Value);
            }

            foreach (var item in m_ShaderRecordDict)
            {
                ResetAssetBundleNameByRecord(item.Value);
            }

            foreach (var item in m_MeshRecordDict)
            {
                ResetAssetBundleNameByRecord(item.Value);
            }

            foreach (var item in m_AnimationRecordDict)
            {
                ResetAssetBundleNameByRecord(item.Value);
            }

            foreach (var item in m_AudioRecordDict)
            {
                ResetAssetBundleNameByRecord(item.Value, true);
            }

            foreach (var item in m_ConfigRecordDict)
            {
                ResetAssetBundleNameByRecord(item.Value, true);
            }

            foreach (var item in m_SceneRecordDict)
            {
                ResetAssetBundleNameByRecord(item.Value, true);
            }
        }
    }

    /// <summary>
    /// 刷新资源名称
    /// </summary>
    /// <param name="record">资源记录信息</param>
    /// <param name="isRootAsset">根节点资源</param>
    void ResetAssetBundleNameByRecord(ResourceRecord record, bool isRootAsset = false)
    {
        if (!isRootAsset) // 子资源需要被多个资源引用才需要设置包名
        {
            if (record.ReferenceCount > 1)
            {
                ResetAssetBundleName(record.RecordType, record.Name, record.RelativePath, record.RootName);
            }
        }
        else
        {
            ResetAssetBundleName(record.RecordType, record.Name, record.RelativePath, record.RootName);
        }
    }

    /// <summary>
    /// 是否是U3D的资源目录
    /// </summary>
    /// <param name="relativePath"></param>
    /// <returns></returns>
    bool IsUnityResourcePath(string relativePath)
    {
        if (relativePath.Contains("unity_builtin_extra")) // 系统相关内容
        {
            return true;
        }
        if (relativePath.Contains("unity default resources"))
        {
            return true;
        }

        return false;
    }

    /// <summary>
    /// 重设资源的AssetBundle 名称
    /// </summary>
    /// <param name="recordType"></param>
    /// <param name="assetName"></param>
    /// <param name="relativePath"></param>
    /// <param name="rootName"></param>

    void ResetAssetBundleName(ResourceRecordType recordType, string assetName, string relativePath, string rootName)
    {
        if (IsUnityResourcePath(relativePath))
        {
            return;
        }

        AssetImporter assetImporter = AssetImporter.GetAtPath(relativePath);
        if (assetImporter == null)
        {
            Debug.LogFormat("Can't find asset[{0}] in path[{1}] of asset type[{2}] in prefab[{3}]", assetName, relativePath, recordType, rootName);
            return;
        }
        assetImporter.assetBundleName = GetAssetBundleName(recordType, assetName);
    }

    /// <summary>
    /// 获取AssetBundle的名称
    /// </summary>
    /// <param name="recordType">资源类型</param>
    /// <param name="assetName">资源原始名称</param>
    /// <returns></returns>
    string GetAssetBundleName(ResourceRecordType recordType, string assetName)
    {
        string headString = GetAssetBundleHeadName(recordType);
        if (!string.IsNullOrEmpty(headString))
        {
            if (!assetName.ToLower().StartsWith(headString.ToLower()))
            {
                assetName = string.Format("{0}{1}", headString, assetName);
            }
        }
        return assetName;
    }

    /// <summary>
    /// 获取AssetBundle 的文件开头名称
    /// </summary>
    /// <param name="recordType">资源类型</param>
    /// <returns></returns>
    string GetAssetBundleHeadName(ResourceRecordType recordType)
    {
        string headString = string.Empty;
        switch (recordType)
        {
            case ResourceRecordType.Prefab:
                headString = "prefab_";
                break;
            case ResourceRecordType.Material:
                headString = "mat_";
                break;
            case ResourceRecordType.Texture:
                headString = "texture_";
                break;
            case ResourceRecordType.Animator:
                headString = "ani_";
                break;
            case ResourceRecordType.AudioClip:
                headString = "audioclip_";
                break;
            case ResourceRecordType.Shader:
                headString = "shader_";
                break;
            case ResourceRecordType.Mesh:
                headString = "fbx_";
                break;
            case ResourceRecordType.Config:
                headString = "config_";
                break;
            case ResourceRecordType.Scene:
                headString = "sence_";
                break;
            default:
                break;
        }
        return headString;
    }

    #region 添加纪录信息

    /// <summary>
    /// 添加纪录信息
    /// </summary>
    /// <param name="recordType">类型</param>
    /// <param name="assetName">名称</param>
    /// <param name="relativePath">相对路径</param>
    /// <param name="rootName">根信息</param>
    public void AddRecord(ResourceRecordType recordType, string assetName, string relativePath, string rootName)
    {
        switch (recordType)
        {
            case ResourceRecordType.Prefab:
                AddToPrefabRecordDict(assetName, relativePath);
                break;
            case ResourceRecordType.Material:
                AddRecordToDict(recordType, m_MaterialRecordDict, assetName, relativePath, rootName);
                break;
            case ResourceRecordType.Texture:
                AddRecordToDict(recordType, m_TextureRecordDict, assetName, relativePath, rootName);
                break;
            case ResourceRecordType.Animator:
                AddRecordToDict(recordType, m_AnimationRecordDict, assetName, relativePath, rootName);
                break;
            case ResourceRecordType.Shader:
                AddRecordToDict(recordType, m_ShaderRecordDict, assetName, relativePath, rootName);
                break;
            case ResourceRecordType.Mesh:
                AddRecordToDict(recordType, m_MeshRecordDict, assetName, relativePath, rootName);
                break;
            case ResourceRecordType.AudioClip:
                AddRecordToDict(recordType, m_AudioRecordDict, assetName, relativePath, rootName);
                break;
            case ResourceRecordType.Config:
                AddRecordToDict(recordType, m_ConfigRecordDict, assetName, relativePath, rootName);
                break;
            case ResourceRecordType.Scene:
                AddRecordToDict(recordType, m_SceneRecordDict, assetName, relativePath, rootName);
                break;
            default:
                break;
        }
    }

    /// <summary>
    /// 添加预制件信息
    /// </summary>
    /// <param name="assetName"></param>
    /// <param name="relativePath"></param>
    void AddToPrefabRecordDict(string assetName, string relativePath)
    {
        if (!m_PrefabRecordDict.ContainsKey(assetName))
        {
            m_PrefabRecordDict.Add(assetName, new ResourceRecord()
            {
                Name = assetName,
                RelativePath = relativePath,
                ReferenceCount = 1,
                RecordType = ResourceRecordType.Prefab,
            });
        }
        else
        {
            Debug.LogErrorFormat("Contains same name prefab please check and fix this error! Prefab name[{0}] in path[{1}]", assetName, relativePath);
        }
    }

    /// <summary>
    /// 添加信息到字典中
    /// </summary>
    /// <param name="recordType"></param>
    /// <param name="recordDict"></param>
    /// <param name="assetName"></param>
    /// <param name="relativePath"></param>
    /// <param name="rootTag"></param>
    void AddRecordToDict(ResourceRecordType recordType, Dictionary<string, ResourceRecord> recordDict, string assetName, string relativePath, string rootTag)
    {
        if (recordDict.ContainsKey(assetName))
        {
            if (recordDict[assetName].RelativePath == relativePath)
            {
                recordDict[assetName].ReferenceCount += 1; // 引用计数+1
            }
            else
            {
                Debug.LogErrorFormat("{0} repeart name[{1}] whit path:[{2}] and path:[{3}], please check it!", recordType, assetName, recordDict[assetName].RelativePath, relativePath);
            }
        }
        else
        {
            recordDict.Add(assetName, new ResourceRecord()
            {
                Name = assetName,
                RelativePath = relativePath,
                ReferenceCount = 1,
                RecordType = recordType,
                RootName = rootTag,
            });
        }
    }

    #endregion
}
